<?php
/***********************************************************************
 * @package     IvanEngine
 * @subpackage  Framework
 * @author      Ivan <ivanzx@msn.com>
 * @created     2010-06-01
 ***********************************************************************/
if(defined("IVANENGINE_FRAMEWORK_WINDOWMANAGER"))
    die("Redefinition macro in :".__FILE__."(".__LINE__.")");
define("IVANENGINE_FRAMEWORK_WINDOWMANAGER", true);

require_once (dirname(__FILE__).'/Common.php');
require_once (dirname(__FILE__).'/Window.php');

class CWindowManager extends CSingleton
{
    const XML_TAG       = 'windows';
    const STORAGE_KEY   = 'windows';
    const SCRIPT_WIN    = 'scriptwindow';
    
    static protected $m_this            = null;
    
    protected
        $m_keepdown         = null,
        $m_windowMap        = null,
        $m_root             = null,
        $m_winJsFile        = null,
        $m_winStorage       = null;
        
    public function __construct()
    {
        parent::__construct();
        $this->m_keepdown       = new CVector();
        $this->m_windowMap      = new CMap();
        CWindow::_AddAttrToList();
    }

    public function __destruct()
    {
        unset($this->m_keepdown);
        unset($this->m_windowMap);
        unset($this->m_root);
        unset($this->m_winStorage);
        parent::__destruct();
    }
    
    static public function Get()
    {
        if( self::$m_this == null )
        {
            parent::StartSingleton();
            self::$m_this = new CWindowManager();
            parent::EndSingleton();
        }
        return self::$m_this;
    }
    
    public function Initialize()
    {
        //$xmlFile  = M_ENGINE_PATH.M_DS.'Config'.M_DS.'Windows.xml';
        $cacheFile= CCacheManager::Get()->GetCacheFilePath('Config/Windows.dat');
        $this->m_winJsFile= CCacheManager::Get()->GetCacheFilePath('Config/Windows.js');
        $pluginName = CRequest::Get()->GetParameter('plugin');
        
        // if first enter, clear all window in storage
        if( empty($pluginName) ){
            CContext::Get()->GetStorage()->Write(self::STORAGE_KEY, null);
        }
        
        // get current window from storage
        $this->Update();
        
        // load windows from cache file
        //CCacheManager::Get()->AddCacheFile($xmlFile, 
        //    new CCacheCallback("_LoadWindows", $this), $cacheFile);
        $this->m_root   = new CWindow(CWindow::ROOT_NAME);
        $this->AddWindow($this->m_root);
        $this->Keepdown($this->m_root->GetName());
    }
    
    public function Update()
    {
        $this->m_winStorage = unserialize(
            CContext::Get()->GetStorage()->Read(self::STORAGE_KEY));
        if( empty($this->m_winStorage) ){
            $this->m_winStorage = new CVector();
            CContext::Get()->GetStorage()->Write(
                self::STORAGE_KEY, serialize($windowList));
        }
    }
    
    public function & GetRoot()
    {
        return $this->m_root;
    }
    
    public function GetWindow($winName)
    {
        return $this->m_windowMap->Get($winName);
    }
    
    public function AddWindow(CWindow & $win)
    {
        $this->m_windowMap->Add($win->GetName(), $win);
    }
    
    public function HasWindow($winName)
    {
        return $this->m_windowMap->Has($winName);
    }
    
    public function AddToStorage($winName)
    {
        if( !$this->m_winStorage->Has(CWindow::ID($winName)) ){
            $this->m_winStorage->Add(CWindow::ID($winName));
        }
        
        CContext::Get()->GetStorage()->Write(
            self::STORAGE_KEY, serialize($this->m_winStorage));
    }
    
    public function HasInStorage($winName)
    {
        return $this->m_winStorage->Has(CWindow::ID($winName));
    }
    
    public function ClearStorage()
    {
        $jsCode = '';
        foreach( $this->m_winStorage as $name )
        {
            if( !$this->m_keepdown->Has($name)){
                $jsCode .= '$(\'#'.$name.'\').remove();'.M_WARP;
                $this->m_winStorage->Remove($name);
            }
        }
        
        CContext::Get()->GetStorage()->Write(
            self::STORAGE_KEY, serialize($this->m_winStorage));
            
        return $jsCode;
    }
    
    public function Keepdown($winName)
    {
        $this->m_keepdown->Add(CWindow::ID($winName));
    }
    
    public function Clear()
    {
        foreach( $this->m_windowMap as $name => $win )
        {
            if( !$this->m_keepdown->Has(CWindow::ID($name)) ){
                $win->GetParent()->RemoveChild($name);
                $this->m_windowMap->Remove($name);
                unset($win);
            }
        }

        return $this->ClearStorage();
    }
    
    public function _LoadWindows($isGenerate, $origin, $cache)
    {
        if( $isGenerate || !CFileHelper::IsExsit($this->m_winJsFile) )
        {
            $xml    = new CXml(CXml::NST_ATTR, 'name');
            $xml->Load($origin);
            $rootName       = $xml->GetRoot()->GetName();
            if( strtolower($rootName) != CWindow::ROOT_NAME ){
                throw new CExceptionInvalidArgument(
                    'root window must be \''.CWindow::ROOT_NAME
                    .'\' attribute in: <br>'.$origin);
            }
            $this->m_root->FromXmlNode($xml->GetRoot());
            $this->m_root->AddChildToManager();
            
            // generate js code for windows
            $winDivCode = 'document.write(\''.
                $this->m_root->GetHtmlCode().'\');'.M_WARP;
            $winJSCode  = '$(function(){'.M_WARP.
                $this->m_root->GetJSCode().'});';
            CFileHelper::Write($this->m_winJsFile, 
                $winDivCode.M_WARP.$winJSCode, null);
                
            // save windows object to cache file
            $data   = serialize($this->m_root);
            CFileHelper::Write($cache, $data);
        }else{
            $data = CFileHelper::Read($cache);
            $this->m_root   = null;
            $this->m_root   = unserialize($data);
            $this->m_root->AddChildToManager();
            CLog::Get()->Note('WindowManager initialized from cache file.');
        }
    }
    
    public function _FindWindowInXmlNode(DOMNode $node, $name, $value)
    {
        if( $name == '' || $node == null ){
            return null;
        }
        
        if( get_class($node) != "DOMElement" && get_class($node) != "DOMNode")
            return null;
            
        $nameVal = $node->getAttribute($name);
        if( $nameVal == $value ){
            return $node;
        }
        if( $node->hasChildNodes() )
        {
            foreach( $node->childNodes as $child )
            {
                $result = $this->_FindWindowInXmlNode($child, $name, $value);
                if( $result )return $result;
            }
        }
        return null;
    }
}
?>
